Reflecting on Shared Assemblies

The Assembly.Load() method has been overloaded a number of times. One variation allows you to specify a culture value (for localized assemblies) as well as a version number and public key token value (for shared assemblies). Collectively speaking, the set of items identifying an assembly is termed the display name. The format of a display name is a comma-delimited string of name/value pairs that begins with the friendly name of the assembly, followed by optional qualifiers (that may appear in any order). Here is the template to follow (optional items appear in parentheses):

Name (,Version = major.minor.build.revision) (,Culture = culture token)
(,PublicKeyToken= public key token)

When you’re crafting a display name, the convention PublicKeyToken=null indicates that binding and matching against a non–strongly named assembly is required. Additionally, Culture="" indicates matching against the default culture of the target machine, for example:

// Load version 1.0.0.0 of CarLibrary using the default culture.
Assembly a =
	Assembly.Load(@"CarLibrary, Version=1.0.0.0, PublicKeyToken=null, Culture=""");

Also be aware that the System.Reflection namespace supplies the AssemblyName type, which allows you to represent the preceding string information in a handy object variable. Typically, this class is used in conjunction with System.Version, which is an OO wrapper around an assembly’s version number. Once you have established the display name, it can then be passed into the overloaded Assembly.Load() method:

// Make use of AssemblyName to define the display name.
AssemblyName asmName;
asmName = new AssemblyName();
asmName.Name = "CarLibrary";
Version v = new Version("1.0.0.0");
asmName.Version = v;
Assembly a = Assembly.Load(asmName);

To load a shared assembly from the GAC, the Assembly.Load() parameter must specify a PublicKeyToken value. For example, assume you have a new Console Application named SharedAsmReflector, and wish to load version 4.0.0.0 of the System.Windows.Forms.dll assembly provided by the .NET base class libraries. Given that the number of types in this assembly is quite large, the following application only prints out the names of public enums, using a simple LINQ query:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Reflection;
using System.IO;

namespace SharedAsmReflector
{
    public class SharedAsmReflector
    {
        private static void DisplayInfo(Assembly a)
        {
            Console.WriteLine("***** Info about Assembly *****");
            Console.WriteLine("Loaded from GAC? {0}", a.GlobalAssemblyCache);
            Console.WriteLine("Asm Name: {0}", a.GetName().Name);
            Console.WriteLine("Asm Version: {0}", a.GetName().Version);
            Console.WriteLine("Asm Culture: {0}",
                a.GetName().CultureInfo.DisplayName);
            Console.WriteLine("\nHere are the public enums:");
            
            // Use a LINQ query to find the public enums.
            Type[] types = a.GetTypes();
            var publicEnums = from pe in types where pe.IsEnum &&
                pe.IsPublic select pe;
            
            foreach (var pe in publicEnums)
            {
                Console.WriteLine(pe);
            }
        }
        
        static void Main(string[] args)
        {
            Console.WriteLine("***** The Shared Asm Reflector App *****\n");

            // Load System.Windows.Forms.dll from GAC.
            string displayName = null;
            displayName = "System.Windows.Forms," +
                "Version=4.0.0.0," +
                "PublicKeyToken=b77a5c561934e089," +
                @"Culture=""";
            Assembly asm = Assembly.Load(displayName);
            DisplayInfo(asm);
            Console.WriteLine("Done!");
            Console.ReadLine();
        }
    }
}

Source Code The SharedAsmReflector project is included in the Chapter 15 subdirectory.

At this point, you should understand how to use some of the core members of the System.Reflection namespace to discover metadata at runtime. Of course, I realize despite the “cool factor,” you likely will not need to build custom object browsers at your place of employment too often. Do recall, however, that reflection services are the foundation for a number of very common programming activities, including late binding.